package com.rc.evcharger.protocol.ylevcharger.netty.server;

import com.alibaba.fastjson.JSON;
import com.rc.evcharger.common.base.AbstractTerminalMessage;
import com.rc.evcharger.common.code.YlControlCode;
import com.rc.evcharger.common.config.RabbitListenerConstant;
import com.rc.evcharger.common.mq.MqProducer;
import com.rc.evcharger.common.utils.NumberUtil;
import com.rc.evcharger.common.utils.StringUtil;
import com.rc.evcharger.protocol.ylevcharger.action.YlCommAction;
import com.rc.evcharger.protocol.ylevcharger.netty.listener.YlNettyListener;
import com.rc.mutievcharger.dto.ylevcharger.terminal.YlTerminalMessage;
import com.rc.mutievcharger.dto.ylevcharger.utils.YlMessageUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

/**
 * netty消息处理器，处理各种指令
 */
public class YlMessageHandler {
    private static Logger logger = LoggerFactory.getLogger(YlMessageHandler.class);

    private YlCommAction ylCommAction = null;
    private MqProducer mqProducer = null;
    private YlPacketHandler ylPacketHandler;

    /**
     * 从application中加载ReadAction对象
     */
    public YlMessageHandler() {
        ApplicationContext ac = YlNettyListener.getApplicationContext();
        mqProducer = (MqProducer) ac.getBean("mqProducer");
        ylPacketHandler = (YlPacketHandler) ac.getBean("ylPacketHandler");
        ylCommAction = (YlCommAction) ac.getBean("ylCommAction");
    }

    /**
     * 公用处理请求
     *
     * @return
     */
    public String doAction(AbstractTerminalMessage abstractMessage, String channelId) {

        YlTerminalMessage message = (YlTerminalMessage) abstractMessage;

        logger.warn("YL收到的指令:{}", message.getBody());

        String response = "";
        try {
            YlNettyChannelHandler nettyChannelHandler = YlNettyChannelHandler.newInstance();
            if (nettyChannelHandler.getChannel(channelId) == null) { //如果连接为空不返回信息给桩，让桩重新登录
                return "";
            }

            YLNettyPileHandler nettyPileHandler = YLNettyPileHandler.newInstance();
            String dataJson = JSON.toJSONString(message);

            // 登录成功将终端逻辑地址放进map中，所有逻辑分本地执行和经MQ异步执行
            switch (message.getContral()) {
                case YlControlCode.LOGIN_6A: //登录
                    //本地执行
                    response = ylCommAction.login(message);

                    if (response.length() > 0) {
                        logger.info("YL登录的channelId：" + channelId);
                        String channelId0 = nettyPileHandler.get(message.getTerminalId());
                        if (channelId0 != null && !channelId.equals(channelId0)) {//如果存在旧连接，就要先关闭
                            if (nettyChannelHandler.getChannel(channelId0) != null) {
                                nettyChannelHandler.getChannel(channelId0).close();
                            }
                        }
                        nettyPileHandler.add(message.getTerminalId(), channelId);

                        logger.warn("YL通道ID与逻辑地址" + message.getTerminalId() + ": id:" + nettyPileHandler.get(message.getTerminalId()));

                        //发送MQ消息由外部模块处理
                        mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_6A_QUEUE, dataJson);
                    }

                    break;
                case YlControlCode.HEARTBEAT_MONITOR_66://心跳

                    //防止发送指令失败
                    String channelId0 = nettyPileHandler.get(message.getTerminalId());
                    if (channelId0 == null) {
                        nettyPileHandler.add(message.getTerminalId(), channelId);
                    }

                    //本地执行
                    response = ylCommAction.hearBeat(message);

                    //发送MQ消息由外部模块处理
                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_66_QUEUE, dataJson);

                    break;
                case YlControlCode.RESP_PRICE_CONFIRMATION://计费模型验证请求应答
                    String terminalId = nettyPileHandler.getRtuaByChannel(channelId);
                    message.setTerminalId(terminalId);
                    //本地执行
                    response = ylCommAction.priceConfirem(message);

                    //发送MQ消息由外部模块处理
//                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_5E_04_QUEUE, dataJson);

                    break;
                case YlControlCode.PRICE_REQUEST://计费模型结果
                    String terminalId1 = nettyPileHandler.getRtuaByChannel(channelId);
                    message.setTerminalId(terminalId1);
                    //本地执行
                    response = ylCommAction.priceRequest(message);

                    //发送MQ消息由外部模块处理
//                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_50_04_QUEUE, dataJson);

                    break;
                case YlControlCode.ELEC_STATUS_68://充电数据上报
                    //本地执行
                    response = ylCommAction.chargeDataReport(message);

                    //发送MQ消息由外部模块处理
                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_68_QUEUE, dataJson);

                    break;
                case YlControlCode.RESP_CONTROL_CHARGE_START_STOP_08://启动响应结果
                    //本地执行
                    response = ylCommAction.startResp(message);

                    //发送MQ消息由外部模块处理
                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_08_QUEUE, dataJson);

                    break;
                case YlControlCode.ELEC_DATA_BALANCE_CA://交易记录
                    //本地执行
                    response = ylCommAction.transactonsReport(message);

                    //发送MQ消息由外部模块处理
                    //延迟一秒，防止与0E指令重复插入订单
                    mqProducer.send(RabbitListenerConstant.DOMAIN1_YL_CONTROLL_CA_QUEUE, dataJson);

                    break;
                default:
            }

            logger.warn("YL回复的指令：" + response + " 回复指令码:{}", message.getContral());
        } catch (Exception e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        }

        return response;
    }

    /**
     * 没有心跳时桩离线
     *
     * @param channelId
     */
    public void logoutWithoutHearbeat(String channelId) {
        YLNettyPileHandler nettyPileHandler = YLNettyPileHandler.newInstance();
        String rtua = nettyPileHandler.getRtuaByChannel(channelId);
        if (rtua == null) {
            logger.error("登出时枪编号为空,对应通道地址:{}", channelId);
            return;
        }
        YlTerminalMessage message = new YlTerminalMessage();
        message.setTerminalId(rtua);
        ylCommAction.logout(message);   //不发送登出报文给电桩,只做相关逻辑处理
        //String dataJson = JSON.toJSONString(message);
        //mqProducer.send(MqConfig.CONTROLL_A2, dataJson);
        logger.warn("电桩" + rtua + "登出");
        nettyPileHandler.remove(rtua);
    }


    /**
     * 发送指令接口
     *
     * @param abstractTerminalMessage
     */
    public static synchronized boolean write(AbstractTerminalMessage abstractTerminalMessage) {

        YlTerminalMessage msg = (YlTerminalMessage) abstractTerminalMessage;
        YLNettyPileHandler nettyPileHandler = YLNettyPileHandler.newInstance();

        //地址需要转化为桩编号
        String terminalId = StringUtil.resolveShTerminal(msg.getTerminalId());

        String channelId = nettyPileHandler.get(terminalId);
        String req = YlMessageUtil.createFrame(msg);
        if (channelId == null) {
            logger.warn("YL发送指令时连接已断开,rtua:", msg.getTerminalId());
            //删除失联的通道ID
            nettyPileHandler.remove(msg.getTerminalId());
            return false;
        }

        YlNettyChannelHandler nettyChannelHandler = YlNettyChannelHandler.newInstance();
        logger.warn("channelId：" + channelId);
        Channel channel = nettyChannelHandler.getChannel(channelId);

        logger.warn("发送的指令：" + req);
        byte[] respTmp = NumberUtil.hexStr2BinArr(req.replace(" ", ""));
        if (respTmp == null) {
            logger.warn("发送的指令为空");
        }
        ByteBuf resp = Unpooled.copiedBuffer(respTmp);
        if (channel == null) {
            logger.warn("channel为空");
        }

        channel.writeAndFlush(resp);
        return true;
    }
}
